/*
 * DataBase.cpp
 *
 *  Created on: 24.03.2009
 *      Author: Konan Andrej
 */

#include "DataBase.h"
DataBase::DataBase()
{

}


DataBase::DataBase( const DataBase& DB)
{

}

DataBase& DataBase::operator =( const DataBase& DB )
{
}

DataBase::DataBase( const DataBaseInfo &Info )
{
    this->Info = Info;
}

DataBase::~DataBase()
{

}

int DataBase::SaveDatabaseToFile()
{
    SaveDatabaseToFile( Info.DBName );
}

int DataBase::SaveDatabaseToFile( const QString& FileName )
{
        //Print( "SaveDatabaseToFile() method is executed" );
	if ( WriteInfoFile( FileName ) == write_error ) return write_error;

        QFile file( QString( "dbms/databases/items/" ) + FileName + QString( ".items" ) );
        //Output( message, "opening file" );

	if ( !file.open( QIODevice::WriteOnly ) ) return write_error;

	QDataStream fout( &file );
	fout.setVersion( QDataStream::Qt_4_4 );

        //Print( "Writing items to file" );
	for( QMap<QString, ItemType>::iterator i = Items.begin(); i != Items.end(); i++ )
		for ( int j=0; j<Info.RecordsNumber; j++ ){
                        //Print( QString::number( j ) + QString("-th field of current item is ") + i->Get( j ) );
			fout << i->Get( j );
		}

	file.close();

        //Output(message, "SaveDatabaseToFile is going to return ok");
	return ok;
}

int DataBase::LoadDatabaseFromFile( const QString& FileName )
{
	//Print( "LoadCurrentDataBase() method is executed" );
	if ( ReadInfoFile( FileName ) == read_error ) return read_error;

        QFile file( QString( "dbms/databases/items/" ) + FileName + QString( ".items" ) );

	if ( !file.open( QIODevice::ReadOnly ) ) return read_error;

	QDataStream fin( &file );
	fin.setVersion( QDataStream::Qt_4_4 );

	ItemType item( Info.RecordsNumber );
	QString buffer = "";

	//Print( "Starting to read items from file" );

	for( int i = 0; i < Info.ItemsNumber; i++ ){
		for ( int j=0; j<Info.RecordsNumber; j++ ){
			fin >> buffer;
			//Print( buffer );
			item.Set( j, buffer );
		}
		Items[ item.Get( Info.KeyField ) ] = item;
	}

	file.close();

        //if ( Info.ItemsNumber == 0 )
        //    Info.DBName = "Income";
        //WriteInfoFile( Info.DBName );
        //if ( Info.ItemsNumber == 24 )
        //    Info.DBName = "Stock";*/

	return ok;
}

int DataBase::ReadInfoFile( const QString& FileName )
{
	//Print( "ReadInfoFile() method is executed" );

        QFile file( QString( "dbms/databases/items/" ) + FileName + QString( ".info" ) );

	if ( !file.open( QIODevice::ReadOnly ) ) return read_error;

	QDataStream fin( &file );
	fin.setVersion( QDataStream::Qt_4_4 );

	fin >> Info.ItemsNumber >> Info.RecordsNumber >> Info.KeyField >> Info.VisibleNumber >> Info.DBName;

	//Print( QString("Info Values:\n") + QString("ItemsNumber: ") + QString::number(Info.ItemsNumber) +
	//		QString( "\nRecordsNumber: " ) + QString::number(Info.RecordsNumber) +
	//		QString( "\nKeyField: " ) + QString::number( Info.KeyField ) );

	QString buffer = "";
	Info.ColumnHeaders.clear();
	for (int i=0; i<Info.RecordsNumber; i++){
		fin >> buffer;
		//Print( buffer );
		Info.ColumnHeaders.push_back( buffer );
	}

        //Reading column width for VisibleNumber columns
        int temp;
        Info.ColumnWidth.clear();
        for (int i=0; i<Info.VisibleNumber; i++ ){
            fin >> temp;
            Info.ColumnWidth.push_back( temp );
        }

	file.close();

	return ok;
}

int DataBase::WriteInfoFile( const QString& FileName )
{
        //Print("WriteInfoFile() method is executed");

        QFile file( QString( "dbms/databases/items/" ) + FileName + QString( ".info" ) );

	if ( !file.open( QIODevice::WriteOnly ) ) return write_error;

	QDataStream fout( &file );
	fout.setVersion( QDataStream::Qt_4_4 );

        //Print( QString("Info Values: \n") + QString("ItemsNumber: ") + QString::number( Info.ItemsNumber ) +
        //                QString("\nRecordsNumber: ") + QString::number( Info.RecordsNumber ) +
        //                QString("\nKeyField: ") + QString::number( Info.KeyField ) );

	fout << Info.ItemsNumber << Info.RecordsNumber << Info.KeyField << Info.VisibleNumber << Info.DBName;

        //Print( QString("ColumnHeaders vector size: ") + QString::number( Info.ColumnHeaders.size() ) );
	for ( int i = 0; i<Info.RecordsNumber; i++ ){
                //Print(Info.ColumnHeaders[i]);
		fout << Info.ColumnHeaders[i];
	}

        //Writing column width for VisibleNumber columns
        //Output(message, QString::number(Info.VisibleNumber) );
        for (int i=0; i<Info.VisibleNumber; i++ ){
            fout << Info.ColumnWidth[i];
        }

        //Output(message, "closing file");
	file.close();

        //Output(message, "WriteInfo file - Ok");
	return ok;
}

int DataBase::GetItem( const QString& Key, ItemType& item ) const
{
	//Print( "GetItem() method is executed" );
	if ( !Items.contains( Key ) ) return find_error;
	//Print( QString("Item with key: \"") + Key + QString( "\" is found" ) );
	item = Items[ Key ];

	return ok;
}

int DataBase::GetItem( const int index, ItemType& item  ) const
{
	int i = 0;
	for( QMap<QString, ItemType>::const_iterator j = Items.begin(); j != Items.end(); j++, i++ )
		if ( i == index ) { item = *j; break; }
        //check for find_error
	return ok;
}

int DataBase::GetItemIndex( const QString &Key ) const
{
        //if ( !Items.contains( Key ) ) return find_error;

        int i = 0;
        for( QMap<QString, ItemType>::const_iterator j = Items.begin(); j != Items.end(); j++, i++ ){
                //Print( QString::number( j.key().indexOf(Key) ) );
                if ( j.key().indexOf(Key) == 0 ) { break; }
            }

        if (i == Items.size()) return -1;

        return i;
}

int DataBase::InsertItem( const ItemType& item )
{
        //Print( "InsertItem() method is executed" );
	if ( Items.contains( item.Get( Info.KeyField ) ) ) return dup_error;

	Info.ItemsNumber++;
	Items[ item.Get( Info.KeyField ) ] = item;

        //verify if new fields are wider then previous. If so we should change column width.
        CheckColumnWidth( item );

        //Print( "Item was successfully inserted" );
        emit ItemAdded();

        SaveDatabaseToFile( Info.DBName );
	return ok;
}

int DataBase::EditItem( const ItemType& item )
{
	if ( !Items.contains( item.Get( Info.KeyField ) ) ) return find_error;

	Items.remove( item.Get( Info.KeyField ) );
	Items[ item.Get( Info.KeyField ) ] = item;

        //verify if new fields are wider then previous. If so we should change column width.
        CheckColumnWidth( item );

	//Print( "Item was succesfully edited" );
        emit ItemEdited();

        SaveDatabaseToFile( Info.DBName );
	return ok;
}

int DataBase::RemoveItem( const ItemType& item )
{
	//Print( "RemoveItem() method is executed" );
	if ( !Items.contains( item.Get( Info.KeyField ) ) ) return find_error;

	Items.remove( item.Get( Info.KeyField ) );
	Info.ItemsNumber--;

	//Print( "Item was succesfully removed" );
        emit ItemRemoved();
        //be aware this signal has no arguments, means that we can implement
        //only inserting and removing las t row

        SaveDatabaseToFile( Info.DBName );
	return ok;
}

void DataBase::GetColumnHeaderVector( QVector<QString>& headers )
{
    headers.clear();
    for ( int i=0; i<Info.ColumnHeaders.size(); i++ )
        headers.push_back( Info.ColumnHeaders[i] );
}

void DataBase::CheckColumnWidth( const ItemType& item )
{
    for (int i=0; i<Info.VisibleNumber; i++)
        if ( item.Get(i).size() * CellK + CellSpace > Info.ColumnWidth[i])
            Info.ColumnWidth[i] = item.Get(i).size() * CellK + CellSpace;
}
